package com.smugmugsoftware.airconcalc.advanced;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;

public class Building implements Parcelable, Serializable {

	private static final long serialVersionUID = 1000L;
	
	public static final int RANGE_LOW = 0;
	public static final int RANGE_MEDIUM = 1;
	public static final int RANGE_HIGH = 2;

	public static final int TIGHTNESS_BEST = 0;
	public static final int TIGHTNESS_AVERAGE = 1;
	public static final int TIGHTNESS_LOOSE = 2;

	private Vector<Room> rooms;

	private String estimatorName;
	private String address;
	private String localeName;
	private int latitude;
	private int summerExternalDryBulb;
	private int summerDesignTemp;
	private int dailyRange;
	private int constructionTightness;

	public Building() {
		rooms = new Vector<Room>();

		latitude = 35;
		summerExternalDryBulb = 90;
		summerDesignTemp = 75;
		dailyRange = 18;
		estimatorName = "(null)";
		address = "(null)";
		localeName = "CUSTOM";
		constructionTightness = TIGHTNESS_AVERAGE;
	}

	public String getEstimatorName() {
		return estimatorName;
	}

	public String getAddress() {
		return address;
	}

	public String getLocaleName() {
		return localeName;
	}

	public int getSummerExternalDryBulb() {
		return summerExternalDryBulb;
	}

	public int getSummerDesignTemp() {
		return summerDesignTemp;
	}

	public void setGlobalValues(String[] strings, int[] data) {
		this.estimatorName = strings[0];
		this.address = strings[1];
		this.localeName = strings[2];
		this.latitude = data[0];
		this.summerDesignTemp = data[1];
		this.summerExternalDryBulb = data[2];
		this.dailyRange = data[3];
		this.constructionTightness = data[4];
	}
	
	public double[] getBuildingLoadBySource(Context context) {
		double[] totalLoads = new double[] { 0, 0, 0, 0, 0, 0, 0 };
		double[] gotLoads = new double[7];
		
		for (Room thisRoom : rooms) {
			gotLoads = thisRoom.getRoomLoadBySource(context);
			
			for (int i = 0; i < totalLoads.length; i++) {
				totalLoads[i] = totalLoads[i] + gotLoads[i];
			}
		}
		
		return totalLoads;
	}

	public double getTotalBuildingLoad(Context context) {
		
		double totalLoad = 0;
		
		for (Room thisRoom : rooms) {
			totalLoad = totalLoad + thisRoom.getTotalRoomLoad(context);
		}
		
		totalLoad = totalLoad + getInfiltrationBTU();
		
		return totalLoad;
	}
	
	public double getBuildingLoadInTons(Context context) {
		
		double totalLoad = getTotalBuildingLoad(context);
		
		totalLoad = totalLoad / 12000;
		
		return totalLoad;
	}
	
	public double getInfiltrationCFM() {

		double totalWallLength = 0;
		double totalWallHeight = 0;
		double airChangeMultiplier = 0;
		
		for (Room thisRoom : rooms) {
			for (Wall thisWall: thisRoom.getWalls()) {
				totalWallLength = totalWallLength + thisWall.getLengthMajorUnit() + (thisWall.getLengthMinorUnit() / 12);
				if (totalWallHeight == 0) {
					totalWallHeight = totalWallHeight + thisWall.getHeightMajorUnit() + (thisWall.getHeightMinorUnit() / 12);
				} else {
					totalWallHeight = totalWallHeight + thisWall.getHeightMajorUnit() + (thisWall.getHeightMinorUnit() / 12);
					totalWallHeight = totalWallHeight / 2;					
				}
			}
			
//			WINTER ONLY!!!!
//			for (SensibleLoad thisLoad : thisRoom.getSensibleLoads()) {
//				if (thisLoad.getConstructionNumber().startsWith("AF")) {
//					if (thisLoad.getConstructionNumber().endsWith("b")) {
//						airChangeMultiplier = airChangeMultiplier + 0.1;
//					} else if (thisLoad.getConstructionNumber().endsWith("a")) {
//						airChangeMultiplier = airChangeMultiplier + 0.2;
//					} else if (thisLoad.getConstructionNumber().endsWith("p")) {
//						airChangeMultiplier = airChangeMultiplier + 0.6;
//				}
//			}
		}
		
		double totalBuildingArea = (((totalWallLength / 4) + (totalWallLength / 16)) * ((totalWallLength / 4) - (totalWallLength / 16)));
		airChangeMultiplier = airChangeMultiplier + getAirChangesPerHour(totalBuildingArea);
		double totalBuildingVolume = totalBuildingArea * totalWallHeight;
		
		return totalBuildingVolume * airChangeMultiplier * 0.0167;
	}
	
	public double getAirChangesPerHour(double area) {
		if (constructionTightness == TIGHTNESS_BEST) {
			return 0.2;
		} else if (constructionTightness == TIGHTNESS_AVERAGE) {
			if (area <= 1500) {
				return 0.5;
			} else {
				return 0.4;
			}
		} else if (constructionTightness == TIGHTNESS_LOOSE) {
			if (area <= 900) {
				return 0.8;
			} else if (area > 900 && area <= 1500) {
				return 0.7;
			} else if (area > 1500 && area <= 2100) {
				return 0.6;
			} else if (area > 2100) {
				return 0.5;
			}
		}
		
		return 0.4;
	}

	public double getInfiltrationBTU() {
		double infiltrationCFM = getInfiltrationCFM();
		int tempDifference = summerExternalDryBulb - summerDesignTemp;
		
		return (infiltrationCFM * tempDifference * 1.1);		
	}
	
	public void addRoom(Room room) {
		Iterator<Room> iterator = getRooms().iterator();
		Room thisRoom = null;
		while (iterator.hasNext()) {
			thisRoom = iterator.next();

			if (thisRoom.getId() == room.getId()) {
				iterator.remove();
				break;
			}
		}

		this.getRooms().add(room);

		Collections.sort(rooms);

		for (int i = 0; i < getRooms().size(); i++) {
			getRooms().get(i).setId((long) (i + 1));
		}
	}

	public Room getNewRoom() {
		return new Room(getRooms().size() + 1, this);
	}

	public void removeRoom(long id) {
		Iterator<Room> iterator = getRooms().iterator();
		Room thisRoom = null;
		while (iterator.hasNext()) {
			thisRoom = iterator.next();

			if (thisRoom.getId() == id + 1) {
				iterator.remove();
				break;
			}
		}

		Collections.sort(rooms);

		for (int i = 0; i < getRooms().size(); i++) {
			getRooms().get(i).setId((long) (i + 1));
		}
	}
	
	public String getConstrutionTightnessString() {
		if (constructionTightness == TIGHTNESS_BEST) {
			return "Tight";
		} else if (constructionTightness == TIGHTNESS_AVERAGE) {
			return "Average";
		} else if (constructionTightness == TIGHTNESS_LOOSE) {
			return "Loose";
		}
		
		return "Average";
	}

	public Vector<Room> getRooms() {
		return rooms;
	}

	public int getInternalTemp() {
		return summerDesignTemp;
	}

	public int getExternalDryBulb() {
		return summerExternalDryBulb;
	}

	public int getDailyRangeInt() {
		return dailyRange;
	}

	public int getConstructionTightness() {
		return constructionTightness;
	}
	
	public int getDailyRangeType() {
		if (dailyRange < 15) {
			return RANGE_LOW;
		} else if (dailyRange >= 15 && dailyRange <= 25) {
			return RANGE_MEDIUM;
		} else if (dailyRange > 25) {
			return RANGE_HIGH;
		}

		return RANGE_MEDIUM;
	}

	public int[] getLocaleData() {
		return new int[] { summerExternalDryBulb - summerDesignTemp , getDailyRangeType() };
	}
	
	public int getActualLatitude() {
		return latitude;
	}
	
	public int getLatitude() {
		
		if (latitude >= 88) {
			return 90;
		} else if (latitude <= -88) {
			return -90;
		}
		
		if (latitude % 5 == 0) {
			return latitude;
		} else if ((latitude + 1) % 5 == 0) {
			return latitude + 1;
		} else if ((latitude + 2) % 5 == 0) {
			return latitude + 2;
		} else if ((latitude - 1) % 5 == 0) {
			return latitude - 1;
		} else if ((latitude - 2) % 5 == 0) {
			return latitude - 2;
		}
		
		return 0;
	}

	public void attachChildren() {
		
		for (int i = 0; i < rooms.size(); i++) {
			if (rooms.get(i).getParent() == null) {
				rooms.get(i).setParent(this);
			}
		}
	}

	public int describeContents() { return 0; }

	public void writeToParcel(Parcel dest, int flags) {

		dest.writeString(estimatorName);
		dest.writeString(address);
		dest.writeString(localeName);
		dest.writeInt(latitude);
		dest.writeInt(summerExternalDryBulb);
		dest.writeInt(summerDesignTemp);
		dest.writeInt(dailyRange);
		dest.writeInt(constructionTightness);

		Room[] roomsParcelArray = (Room[]) rooms.toArray(new Room[rooms.size()]);
		dest.writeParcelableArray(roomsParcelArray, PARCELABLE_WRITE_RETURN_VALUE);
	}

	public static final Parcelable.Creator<Building> CREATOR = new Parcelable.Creator<Building>() {
		public Building createFromParcel(Parcel in) {
			return new Building(in);
		}

		public Building[] newArray(int size) {
			return new Building[size];
		}
	};

	public Building(Parcel p) {

		this.estimatorName = p.readString();
		this.address = p.readString();
		this.localeName = p.readString();
		this.latitude = p.readInt();
		this.summerExternalDryBulb = p.readInt();
		this.summerDesignTemp = p.readInt();
		this.dailyRange = p.readInt();
		this.constructionTightness = p.readInt();

		Parcelable[] roomsParcelArray = (Parcelable[]) p.readParcelableArray(Room.class.getClassLoader());
		this.rooms = new Vector<Room>();
		for (Parcelable thisRoom : roomsParcelArray) {
			rooms.add((Room) thisRoom);
		}
	}
}
